Transform¶

Transfom represent kinds of transform matrixes, including translation, scaling, rotation and projection.

Identity¶

In [1]:
from py3d import Transform
Transform()
Welcome to py3d world, please visit https://tumiz.github.io/scenario/ for more information
Out[1]:
Transform([[1., 0., 0., 0.],
           [0., 1., 0., 0.],
           [0., 0., 1., 0.],
           [0., 0., 0., 1.]])
In [3]:
Transform(n=(2,))
Out[3]:
Transform([[[1., 0., 0., 0.],
            [0., 1., 0., 0.],
            [0., 0., 1., 0.],
            [0., 0., 0., 1.]],

           [[1., 0., 0., 0.],
            [0., 1., 0., 0.],
            [0., 0., 1., 0.],
            [0., 0., 0., 1.]]])

Translation¶

Translation Matrix¶

In py3d, transformations are represented as left-multiplication matrixes, point are represented as row vectors.

Left-multiplication translation matrix¶

In [5]:
from sympy import symbols, Matrix
x, y, z, dx, dy, dz = symbols("x y z dx dy dz")
point = Matrix([x, y, z, 1]).T
translation = Matrix([
    [1, 0, 0, 0],
    [0, 1, 0, 0],
    [0, 0, 1, 0],
    [dx, dy, dz, 1]
])
translation
Out[5]:
$\displaystyle \left[\begin{matrix}1 & 0 & 0 & 0\\0 & 1 & 0 & 0\\0 & 0 & 1 & 0\\dx & dy & dz & 1\end{matrix}\right]$
In [6]:
point * translation
Out[6]:
$\displaystyle \left[\begin{matrix}dx + x & dy + y & dz + z & 1\end{matrix}\right]$
In [7]:
dx_,dy_,dz_ = symbols("dx' dy' dz'")
translation_ = Matrix([
    [1, 0, 0, 0],
    [0, 1, 0, 0],
    [0, 0, 1, 0],
    [dx_, dy_, dz_, 1]
])
translation_ * translation
Out[7]:
$\displaystyle \left[\begin{matrix}1 & 0 & 0 & 0\\0 & 1 & 0 & 0\\0 & 0 & 1 & 0\\dx + dx' & dy + dy' & dz + dz' & 1\end{matrix}\right]$
In [8]:
translation * translation_
Out[8]:
$\displaystyle \left[\begin{matrix}1 & 0 & 0 & 0\\0 & 1 & 0 & 0\\0 & 0 & 1 & 0\\dx + dx' & dy + dy' & dz + dz' & 1\end{matrix}\right]$

Right-multiplication translation matrix¶

In [9]:
translation.T
Out[9]:
$\displaystyle \left[\begin{matrix}1 & 0 & 0 & dx\\0 & 1 & 0 & dy\\0 & 0 & 1 & dz\\0 & 0 & 0 & 1\end{matrix}\right]$
In [10]:
translation.T * point.T
Out[10]:
$\displaystyle \left[\begin{matrix}dx + x\\dy + y\\dz + z\\1\end{matrix}\right]$
In [11]:
from py3d import Vector3
Vector3([2, 3, 4]).as_translation()
Out[11]:
Transform([[1., 0., 0., 0.],
           [0., 1., 0., 0.],
           [0., 0., 1., 0.],
           [2., 3., 4., 1.]])
In [13]:
Transform.from_translation(x=1, n=(2,))
Out[13]:
Transform([[[1., 0., 0., 0.],
            [0., 1., 0., 0.],
            [0., 0., 1., 0.],
            [1., 0., 0., 1.]],

           [[1., 0., 0., 0.],
            [0., 1., 0., 0.],
            [0., 0., 1., 0.],
            [1., 0., 0., 1.]]])

Translate a series of points

In [14]:
import py3d
v = py3d.Viewer()
points = py3d.Vector3.Rand(100)
v.render(points.as_point())
points @= py3d.Transform.from_translation(x=1)
v.render(points.as_point())
v.show()
Out[14]:
py3d

Move a car

In [15]:
import py3d
v = py3d.Viewer()
car = py3d.Utils.Car()
grid = py3d.Utils.Grid(10)
t = 0
while t < 4:
    car.vertex @= py3d.Transform.from_translation(x=0.2)
    v.render(grid, car, t=t)
    t += 0.1
v.show()
Out[15]:
py3d

Scaling¶

In [16]:
from py3d import Vector3
Vector3(x=1, y=2, z=(1, 2, 3)).as_scaling()
Out[16]:
Transform([[[1., 0., 0., 0.],
            [0., 2., 0., 0.],
            [0., 0., 1., 0.],
            [0., 0., 0., 1.]],

           [[1., 0., 0., 0.],
            [0., 2., 0., 0.],
            [0., 0., 2., 0.],
            [0., 0., 0., 1.]],

           [[1., 0., 0., 0.],
            [0., 2., 0., 0.],
            [0., 0., 3., 0.],
            [0., 0., 0., 1.]]])
In [17]:
Transform.from_scaling(x=1, y=-1, z=(1, 2, 3))
Out[17]:
Transform([[[ 1.,  0.,  0.,  0.],
            [ 0., -1.,  0.,  0.],
            [ 0.,  0.,  1.,  0.],
            [ 0.,  0.,  0.,  1.]],

           [[ 1.,  0.,  0.,  0.],
            [ 0., -1.,  0.,  0.],
            [ 0.,  0.,  2.,  0.],
            [ 0.,  0.,  0.,  1.]],

           [[ 1.,  0.,  0.,  0.],
            [ 0., -1.,  0.,  0.],
            [ 0.,  0.,  3.,  0.],
            [ 0.,  0.,  0.,  1.]]])
In [18]:
from py3d import Vector3, Transform
points = (Vector3.Rand(1000)-0.5).U @ Transform.from_scaling(x=2)
points.as_point().render()
Out[18]:
py3d

Rotation¶

Projection¶

Camera and scene¶

In [19]:
import py3d
v=py3d.Viewer()
v.render(py3d.Utils.Grid())
camera=py3d.Utils.Axis(2)
camera.vertex @= py3d.Transform.from_translation([0,0,5]) @ py3d.Transform.from_rpy([py3d.pi/3,py3d.pi/6,0])
line=camera.vertex[0,0].as_vector()
v.render(camera,line)
v.show()
Out[19]:
py3d
In [20]:
camera.vertex[0][0]
Out[20]:
Vector3([ 2.5       , -3.75      ,  2.16506351])

Project 3d points on xy plane¶

In [21]:
import py3d
v=py3d.Viewer()
p=(py3d.Vector3.Rand(1000)-0.5).U+py3d.Vector3(x=1,y=1,z=2)
v.render(p.as_point())
p.z=0
v.render(p.as_point(), py3d.Utils.Grid())
v.show()
Out[21]:
py3d

Orthographic projection¶

In [22]:
import sympy
l, r, t, b, n, f = sympy.symbols("l r t b n f")
m_scale = sympy.Matrix([
    [2/(r-l), 0, 0, 0],
    [0, 2/(t-b), 0, 0],
    [0, 0, 2/(n-f), 0],
    [0, 0, 0, 1]
])
m_translate = sympy.Matrix([
    [1, 0, 0, -(l+r)/2],
    [0, 1, 0, -(b+t)/2],
    [0, 0, 1, -(f+n)/2],
    [0, 0, 0, 1]
])
o=sympy.simplify(m_scale*m_translate).transpose()
o
Out[22]:
$\displaystyle \left[\begin{matrix}\frac{2}{- l + r} & 0 & 0 & 0\\0 & \frac{2}{- b + t} & 0 & 0\\0 & 0 & - \frac{2}{f - n} & 0\\\frac{l + r}{l - r} & \frac{b + t}{b - t} & \frac{f + n}{f - n} & 1\end{matrix}\right]$
In [23]:
w, h = sympy.symbols("w h")
o=o.subs(l, -w/2).subs(r, w/2).subs(t, h/2).subs(b, -h/2)
o
Out[23]:
$\displaystyle \left[\begin{matrix}\frac{2}{w} & 0 & 0 & 0\\0 & \frac{2}{h} & 0 & 0\\0 & 0 & - \frac{2}{f - n} & 0\\0 & 0 & \frac{f + n}{f - n} & 1\end{matrix}\right]$

Use perspective fov and aspect to define a orthographic projection

In [24]:
fov, aspect, distance = sympy.symbols("fov a d")
o=o.subs(w, aspect * h).subs(h, distance*sympy.tan(fov/2)*2)
o
Out[24]:
$\displaystyle \left[\begin{matrix}\frac{1}{a d \tan{\left(\frac{fov}{2} \right)}} & 0 & 0 & 0\\0 & \frac{1}{d \tan{\left(\frac{fov}{2} \right)}} & 0 & 0\\0 & 0 & - \frac{2}{f - n} & 0\\0 & 0 & \frac{f + n}{f - n} & 1\end{matrix}\right]$
In [25]:
x, y, z = sympy.symbols("x y z")
sympy.Matrix([x, y, z, 1]).T @ o
Out[25]:
$\displaystyle \left[\begin{matrix}\frac{x}{a d \tan{\left(\frac{fov}{2} \right)}} & \frac{y}{d \tan{\left(\frac{fov}{2} \right)}} & - \frac{2 z}{f - n} + \frac{f + n}{f - n} & 1\end{matrix}\right]$

Perspective projection¶

In [26]:
from py3d import Transform, pi, Vector3
projection = Transform.from_perspective(pi/2, 1.2, 0, 1000)
projection
Out[26]:
array([[ 0.83333333,  0.        ,  0.        ,  0.        ],
       [ 0.        ,  1.        ,  0.        ,  0.        ],
       [ 0.        ,  0.        , -1.        ,  1.        ],
       [ 0.        ,  0.        , -0.        ,  0.        ]])
In [27]:
from py3d import Camera, pi, Vector3, Transform
import matplotlib.pyplot as plt
camera = Camera()
camera.transform.translation = Transform.from_translation([0, 0, 10])
camera.transform.rotation = Transform.from_rpy([0, 0, 0])
camera.projection = Transform.from_perspective(pi/3, 1, 1, 1000)
points = Vector3.Rand(100)
proj = points @ camera.matrix
plt.gca().set_aspect(1)
plt.scatter(proj.x, proj.y)
Out[27]:
<matplotlib.collections.PathCollection at 0x7ff4bbbc7a90>

↑Top

←Home